﻿#include "Stream.h"
#include "../log/SysLog.h"
#include "../util/SystemHelper.h"
#include "../util/TextUtil.h"

Stream::Stream(std::string device)
	: m_call(nullptr)
	, m_contex(nullptr)
	, m_run(true)
	, m_device(device)
{
}

Stream::~Stream()
{
}

void Stream::Start(std::string url)
{
	m_run = true;
	m_thread = std::thread([&](std::string url){
		// 视频信息
		int width = 0, height = 0, fps = 25;

		// 创建视频捕获器
		cv::VideoCapture cap = cv::VideoCapture();

		// 设置采集的视频格式
		// cap.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('H', '2', '6', '4'));
		// 不要自动将捕获的图像从YUV转换为BGR
		// cap.set(cv::CAP_PROP_CONVERT_RGB, 0);
		while (m_run)
		{
			// 设备未连接
			if (!cap.isOpened())
			{
				// 打开本地摄像头
				if (TextUtil::get_mutable_instance().IsInteger(url))
				{
					// 打开视频流:设置编码格式为RGB24
					if (!cap.open(std::stoi(url)))
					{
						LOG_WARN("open local camera [{}] failed, please insert the camera.", url);
						std::this_thread::sleep_for(std::chrono::seconds(5));
						continue;
					}
				}
				// 打开网络摄像机
				else
				{
					// 获取rtsp地址
					int port = 0;
					std::string ip = TextUtil::get_mutable_instance().GetIpFromRtspUrl(url, port);
					if (ip.empty() || 0 == port)
					{
						LOG_ERROR("invalid rtsp url[{}] for device [{}].", url, m_device);
						std::this_thread::sleep_for(std::chrono::seconds(5));
						continue;
					}
					// 设备不可连接
					if (!SystemHelper::get_mutable_instance().IsPortOpen(ip, port))
					{
						LOG_WARN("{} can not connect, try again later", url);
						std::this_thread::sleep_for(std::chrono::seconds(5));
						continue;
					}
					// 打开视频流:设置编码格式为RGB24
					std::string ffmpeg_options = "rtsp_transport;tcp -pix_fmt rgb24";
					if (!cap.open(url, cv::CAP_FFMPEG))
					{
						LOG_WARN("open rtsp[{}] failed, try again later", url);
						std::this_thread::sleep_for(std::chrono::seconds(5));
						continue;
					}
				}

				LOG_INFO("Open device {} success.", url);
				
				// 获取视频宽高信息
				width = cap.get(cv::CAP_PROP_FRAME_WIDTH);
				height = cap.get(cv::CAP_PROP_FRAME_HEIGHT);
				// 通过USB可能读取不到帧率
				fps = cap.get(cv::CAP_PROP_FPS);
				fps = std::min<int>(fps, 120);
				// USB读取不到则设置默认帧率
				if (fps <= 0) {
					cap.set(cv::CAP_PROP_FPS, 25);
					fps = 25;
				}
			}
			// 视频已打开
			else
			{
				// 读取一帧
				cv::Mat frame;
				// 指向下一帧
				cap.grab();
				// 读取失败
				if (!cap.retrieve(frame))
				{
					cap.release();
					cap = cv::VideoCapture();
					std::this_thread::sleep_for(std::chrono::seconds(1));
					continue;
				}

				int channel = frame.channels();
				int type = frame.type();
				int depth = frame.depth();

				// 默认采集为BGR，如果设置了不做RGB转换则需要手动YUV转BGR
				// cv::Mat bgrFrame;
				// cv::cvtColor(frame, bgrFrame, cv::COLOR_YUV2BGR);

				// 数据回调
				if (m_call)
				{
					m_call(m_device, width, height, fps, frame, m_contex);
				}
			}
		}
		// 释放资源
		cap.release();
	}, url);
}

void Stream::Close()
{
	m_run = false;
	if (m_thread.joinable())
	{
		m_thread.join();
	}
}

void Stream::SetCallback(VIDEOCB call, void* context)
{
	m_call = call;
	m_contex = context;
}

VIDEOCB Stream::GetCallback()
{
	return m_call;
}

void* Stream::GetContext()
{
	return m_contex;
}